package cc.rengu.oltp.service.base;

import cc.rengu.jradp.schedule.AbstractSchedule;
import cc.rengu.jradp.schedule.ScheduleImpl;
import cc.rengu.oltp.service.common.enums.OltpRpcdEnum;
import cc.rengu.oltp.service.model.BizException;

import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

/**
 * The type Base base.
 */
public abstract class RadpService extends AbstractSchedule implements ScheduleImpl {
    @Override
    public int initService(String s) {
        return bizInit(s);
    }

    @Override
    public int termService(String s) {
        return bizTerminate(s);
    }

    @Override
    public int service(String s, int i) {
        return bizProcess(s, i);
    }

    /**
     * Biz init int.
     *
     * @param s the s
     * @return the int
     */
    protected abstract int bizInit(String s);

    /**
     * Biz process int.
     *
     * @param s the s
     * @param i the
     * @return the int
     */
    protected abstract int bizProcess(String s, int i);

    /**
     * Biz terminate int.
     *
     * @param s the s
     * @return the int
     */
    protected abstract int bizTerminate(String s);

    /**
     * 业务自定义注解方法执行
     *
     * @param annoClasz 注解类
     */
    protected void invokeBizAnnoMethod(Class annoClasz) {
        try {
            Method[] methods = this.getClass().getDeclaredMethods();
            for (Method method : methods) {
                boolean methodHasAnno = method.isAnnotationPresent(annoClasz);
                if (methodHasAnno) {
                    /* 执行对应的注解方法 */
                    rglog.info("正在执行注解类{}的自定义方法:{}", annoClasz.getName(), method.getName());
                    method.setAccessible(true);
                    method.invoke(this.getClass().newInstance());
                }
            }
        } catch (Exception e) {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
            if (e instanceof InvocationTargetException) {
                Throwable throwable = ((InvocationTargetException) e).getTargetException();
                if (throwable instanceof BizException) {
                    String respCode = ((BizException) throwable).getCode();
                    String respDesc = throwable.getMessage();
                    rglog.error("业务处理失败，业务返回码:<{}>，业务返回信息:<{}>", respCode, respDesc);
                    throw new BizException(respCode, respDesc);
                } else {
                    rglog.error(byteArrayOutputStream.toString());
                    throw new BizException(OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespCode(), e.getMessage());
                }
            } else {
                rglog.error("用户自定义实现流程处理失败:{}", byteArrayOutputStream.toString());
                throw new BizException(OltpRpcdEnum.CUSTOM_ANNO_METHOD_PROCESS_ERROR);
            }
        }
    }

    /**
     * 业务自定义注解类执行
     *
     * @param annoClasz 注解类
     * @param requests  调用方法请求参数集
     * @return 调用方法执行结果
     */
    protected Object invokeBizAnnoMethod(Class annoClasz, Object... requests) {
        try {
            Method[] methods = this.getClass().getDeclaredMethods();
            for (Method method : methods) {
                boolean isThisMethod = false;
                boolean methodHasAnno = method.isAnnotationPresent(annoClasz);
                if (methodHasAnno) {
                    Type[] genericParameterTypes = method.getGenericParameterTypes();
                    if (requests.length == genericParameterTypes.length) {
                        for (int i = 0; i < requests.length; i++) {
                            if (genericParameterTypes[i].getTypeName().equals(requests[i].getClass().getName())) {
                                isThisMethod = true;
                            } else if (genericParameterTypes[i] instanceof ParameterizedType) {
                                Class[] claszs = requests[i].getClass().getInterfaces();
                                String name = method.getParameterTypes()[i].getTypeName();
                                List<String> claszNames = Arrays.stream(claszs).map(Class::getName).collect(Collectors.toList());
                                if (claszNames.contains(name)) {
                                    isThisMethod = true;
                                }
                            }
                        }
                        if (isThisMethod) {
                            /* 执行对应的注解方法 */
                            rglog.info("正在执行注解类{}的自定义方法:{}", annoClasz.getName(), method.getName());
                            method.setAccessible(true);
                            return method.invoke(this.getClass().newInstance(), requests);
                        }
                    }
                }
            }
        } catch (Exception e) {
            if (e instanceof InvocationTargetException) {
                Throwable throwable = ((InvocationTargetException) e).getTargetException();
                if (throwable instanceof BizException) {
                    String respCode = ((BizException) throwable).getCode();
                    String respDesc = throwable.getMessage();
                    rglog.error("业务处理失败，业务返回码:<{}>，业务返回信息:<{}>", respCode, respDesc);
                    throw new BizException(respCode, respDesc);
                } else {
                    rglog.error(e.getMessage());
                    throw new BizException(OltpRpcdEnum.OLTP_PROCESS_ERROR.getRespCode(), e.getMessage());
                }
            } else {
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                e.printStackTrace(new PrintWriter(byteArrayOutputStream, true));
                rglog.error("用户自定义实现流程处理失败:{}", byteArrayOutputStream.toString());
                throw new BizException(OltpRpcdEnum.CUSTOM_ANNO_METHOD_PROCESS_ERROR);
            }
        }
        return null;
    }
}
